package org.xxpay.manage.settlement.ctrl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.xxpay.core.common.annotation.MethodLog;
import org.xxpay.core.common.constant.Constant;
import org.xxpay.core.common.constant.MchConstant;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.constant.RetEnum;
import org.xxpay.core.common.domain.BizResponse;
import org.xxpay.core.common.domain.XxPayPageRes;
import org.xxpay.core.common.domain.XxPayResponse;
import org.xxpay.core.common.domain.api.msg.QueryRetMsg;
import org.xxpay.core.common.exception.ServiceException;
import org.xxpay.core.common.util.*;
import org.xxpay.core.common.vo.DBAgentpayConfig;
import org.xxpay.core.entity.AgentpayPassage;
import org.xxpay.core.entity.AgentpayPassageAccount;
import org.xxpay.core.entity.MchAgentpayRecord;
import org.xxpay.core.entity.SysUser;
import org.xxpay.manage.common.ctrl.BaseController;
import org.xxpay.manage.common.service.RpcCommonService;
import org.xxpay.manage.config.service.CommonConfigService;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author: dingzhiwei
 * @date: 17/12/6
 * @description: 代付
 */
@RestController
@RequestMapping(Constant.MGR_CONTROLLER_ROOT_PATH + "/agentpay")
public class AgentpayController extends BaseController {

    private static final MyLog _log = MyLog.getLog(AgentpayController.class);

    @Autowired
    private RpcCommonService rpcCommonService;

    @Autowired
    private CommonConfigService commonConfigService;

    /**
     * 代付列表查询
     * @return
     */
    @RequestMapping("/list")
    @ResponseBody
    public ResponseEntity<?> list(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        MchAgentpayRecord mchAgentpayRecord = getObject(param, MchAgentpayRecord.class);
        if(mchAgentpayRecord == null) mchAgentpayRecord = new MchAgentpayRecord();
        int count = commonService.mchAgentpayService.count(mchAgentpayRecord, getQueryObj(param));
        if(count == 0) return ResponseEntity.ok(XxPayPageRes.buildSuccess());
        List<JSONObject> objects = new LinkedList<>();
        List<MchAgentpayRecord> mchAgentpayRecordList = commonService.mchAgentpayService.select((getPageIndex(param)-1) * getPageSize(param), getPageSize(param), mchAgentpayRecord, getQueryObj(param));

        // 查询商户名称
        Map<String, String> mchNameMap = commonService.mchInfoService.selectNameMap();

        for(MchAgentpayRecord mar : mchAgentpayRecordList) {
            // 取银行卡号
            String accountNo = getCardNo4List(this.getUser().getIsSuperAdmin(), mar.getAccountNo());
            mar.setAccountNo(accountNo);
            JSONObject object = (JSONObject) JSON.toJSON(mar);
            // 默认为空,可能是没开启抢单或者还没有抢单 or  抢单用户为自己
            if(!isEnableSnatch()
                    || StringUtils.isEmpty(mar.getSnatchUserId())
                    || isSupAdmin()
                    || mar.getSnatchUserId().equals(this.getUser().getId()+"")) {
                object.put("displayHandle", 1);  // 前端显示处理
            }else {
                object.put("displayHandle", 0);  // 前端不显示处理
            }
            String mchName = mchNameMap.get(mar.getMchId()+"");
            if(StringUtils.isNotEmpty(mchName)) object.put("mchName", mchName);             // 商户名称
            objects.add(object);

        }
        return ResponseEntity.ok(XxPayPageRes.buildSuccess(objects, count));
    }

    /**
     * 代付记录查询
     * @return
     */
    @RequestMapping("/get")
    @ResponseBody
    public ResponseEntity<?> get(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        String agentpayOrderId = getStringRequired(param, "agentpayOrderId");
        MchAgentpayRecord mchAgentpayRecord = new MchAgentpayRecord();
        mchAgentpayRecord.setAgentpayOrderId(agentpayOrderId);
        mchAgentpayRecord = commonService.mchAgentpayService.find(mchAgentpayRecord);
        JSONObject object = new JSONObject();
        if(mchAgentpayRecord != null) {
            String accountNo = getCardNo4View(mchAgentpayRecord);
            mchAgentpayRecord.setAccountNo(accountNo);
            object = (JSONObject) JSON.toJSON(mchAgentpayRecord);
            object.put("displayGiveUp", 0);  // 前端默认不显示弃单按钮
            // 不为空,可表示已被抢
            if(isEnableSnatch() && StringUtils.isNotBlank(mchAgentpayRecord.getSnatchUserId())) {
                // 管理员或自己可以显示弃单按钮
                if(isSupAdmin() || mchAgentpayRecord.getSnatchUserId().equals(this.getUser().getId()+"")) {
                    object.put("displayGiveUp", 1);  // 前端显示弃单按钮
                }
            }
        }
        return ResponseEntity.ok(XxPayResponse.buildSuccess(object));
    }

    /**
     * 处理抢单
     * 1. 判断平台是否开启了代付抢单模式
     * 2. 处理抢单逻辑
     * @return
     */
    @RequestMapping("/snatch")
    @ResponseBody
    @MethodLog(remark = "抢单处理")
    public ResponseEntity<?> snatch(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        String agentpayOrderId = getStringRequired(param, "agentpayOrderId");
        // 判断代付抢单模式是否开启
        if (!isEnableSnatch()) {
            return ResponseEntity.ok(BizResponse.build("ok"));
        }
        MchAgentpayRecord mchAgentpayRecord = commonService.mchAgentpayService.findByAgentpayOrderId(agentpayOrderId);
        if(mchAgentpayRecord == null) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_COMM_RECORD_NOT_EXIST));
        }
        // 如果是超级管理员,直接返回
        if(this.getUser().getIsSuperAdmin() == MchConstant.PUB_YES) {
            return ResponseEntity.ok(BizResponse.build("ok"));
        }

        if(StringUtils.isBlank(mchAgentpayRecord.getSnatchUserId())) {
            // 尝试抢单
            int snatchResult = commonService.mchAgentpayService.snatchOrder(agentpayOrderId, getUser().getId()+"", getUser().getName());
            // 抢单成功
            if(snatchResult == 1) {
                return ResponseEntity.ok(BizResponse.build("ok"));
            }
            return ResponseEntity.ok(BizResponse.build("该订单已被抢走！！！"));
        }

        // 当前人既是抢单人
        if(mchAgentpayRecord.getSnatchUserId().equals(getUser().getId()+"")) {
            return ResponseEntity.ok(BizResponse.build("ok"));
        }

        return ResponseEntity.ok(BizResponse.build("该订单已被抢走！！！"));

    }

    /**
     * 弃单处理
     * @return
     */
    @RequestMapping("/giveup")
    @ResponseBody
    @MethodLog(remark = "弃单处理")
    public ResponseEntity<?> giveUp(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        String agentpayOrderId = getStringRequired(param, "agentpayOrderId");

        MchAgentpayRecord mchAgentpayRecord = commonService.mchAgentpayService.findByAgentpayOrderId(agentpayOrderId);
        if(mchAgentpayRecord == null) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_COMM_RECORD_NOT_EXIST));
        }
        if(mchAgentpayRecord.getSnatchUserId() == null) {
            return ResponseEntity.ok(XxPayResponse.buildSuccess("该订单不属于你！！！"));
        }

        // 当前人不是抢单人
        if(!isSupAdmin() && !mchAgentpayRecord.getSnatchUserId().equals(getUser().getId()+"")) {
            return ResponseEntity.ok(XxPayResponse.buildSuccess("该订单不属于你！！！"));
        }

        // 弃单
        int result = commonService.mchAgentpayService.giveUpOrder(agentpayOrderId, getUser().getId()+"", isSupAdmin());
        // 弃单成功
        if(result == 1) {
            return ResponseEntity.ok(BizResponse.build("ok"));
        }
        return ResponseEntity.ok(BizResponse.build(RetEnum.RET_COMM_OPERATION_FAIL, "弃单失败！！！"));

    }

    @RequestMapping("/trans_query")
    @ResponseBody
    public ResponseEntity<?> queryTrans(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        String transOrderId = getStringRequired(param, "transOrderId");
        QueryRetMsg msg = rpcCommonService.rpcXxPayTransService.queryTrans(transOrderId);
        if(msg != null && msg.getChannelOriginResponse() != null){
            return ResponseEntity.ok(XxPayResponse.buildSuccess(msg.getChannelOriginResponse()));
        }else {
            return ResponseEntity.ok(XxPayResponse.buildSuccess("查询通道异常"));
        }
    }

    /**
     * 查询统计数据
     * @return
     */
    @RequestMapping("/count")
    @ResponseBody
    public ResponseEntity<?> count(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        Long mchId = getLong(param, "mchId");
        Long supplierExecId = getLong(param, "supplierExecId");
        String agentpayOrderId = getString(param, "agentpayOrderId");
        String transOrderId = getString(param, "transOrderId");
        String accountName = getString(param, "accountName");
        Byte status = getByte(param, "status");
        Byte agentpayChannel = getByte(param, "agentpayChannel");
        String mchOrderNo = getString(param, "mchOrderNo");
        String operatorUserId = getString(param, "operatorUserId");

        // 订单起止时间
        String createTimeStartStr = getString(param, "createTimeStart");
        String createTimeEndStr = getString(param, "createTimeEnd");
        Map allMap = commonService.mchAgentpayService.count4All(mchId, supplierExecId, accountName, agentpayOrderId, transOrderId, status, agentpayChannel, mchOrderNo, operatorUserId, createTimeStartStr, createTimeEndStr);

        JSONObject obj = new JSONObject();
        obj.put("allTotalCount", allMap.get("totalCount"));                         // 所有订单数
        obj.put("allTotalAmount", allMap.get("totalAmount"));                       // 金额
        obj.put("allTotalFee", allMap.get("totalFee"));                             // 费用
        obj.put("allTotalSubAmount", allMap.get("totalSubAmount"));                 // 扣减金额
        return ResponseEntity.ok(XxPayResponse.buildSuccess(obj));
    }



    /** 审核通过 发起转账 */
    @RequestMapping("/auditOK")
    @ResponseBody
    @MethodLog( remark = "代付记录审核通过/发起转账" )
    public ResponseEntity<?> auditOK(HttpServletRequest request) {

        JSONObject param = getJsonParam();
        processAgentpaySuccess(param);

        return ResponseEntity.ok(XxPayResponse.buildSuccess());
    }


    /** 代付记录审核拒绝 */
    @RequestMapping("/auditReject")
    @ResponseBody
    @MethodLog( remark = "代付记录审核拒绝" )
    public ResponseEntity<?> auditReject(HttpServletRequest request) {

        JSONObject param = getJsonParam();
        String agentpayOrderId = getStringRequired(param, "agentpayOrderId");

        MchAgentpayRecord record = commonService.mchAgentpayService.findByAgentpayOrderId(agentpayOrderId);

        if(record == null || record.getStatus() != PayConstant.AGENTPAY_STATUS_WAIT_AUDIT){
            throw new ServiceException(RetEnum.RET_COMM_RECORD_NOT_EXIST);
        }

        rpcCommonService.rpcXxPayAgentpayService.auditReject(record, PayConstant.AGENTPAY_STATUS_WAIT_AUDIT);
        return ResponseEntity.ok(XxPayResponse.buildSuccess());

    }

    @RequestMapping("/exportExcel")
    @ResponseBody
    public String exportExcel(HttpServletRequest request) throws Exception {

        JSONObject param = getJsonParam(request);
        MchAgentpayRecord mchAgentpayRecord = getObject(param, MchAgentpayRecord.class);
        if(mchAgentpayRecord == null) mchAgentpayRecord = new MchAgentpayRecord();
        int count = commonService.mchAgentpayService.count(mchAgentpayRecord, getQueryObj(param));
        if(count > MchConstant.MAX_EXPORT_ROW) return RetEnum.RET_SERVICE_OUT_OF_RANGE_MAX_EXPORT_ROW.getMessage();
        List<MchAgentpayRecord> mchAgentpayRecordList = commonService.mchAgentpayService.select(0, MchConstant.MAX_EXPORT_ROW, mchAgentpayRecord, getQueryObj(param));

        List<List> excelData = new ArrayList<>();
        List header = Arrays.asList(new String[]{"商户ID", "代付单号", "商户单号", "账户名", "账号", "代付金额（元）", "手续费（元）", "扣减账户金额（元）", "状态", "代付渠道", "创建时间"});
        excelData.add(header);
        for(MchAgentpayRecord record : mchAgentpayRecordList){
            List rowData = new ArrayList<>();
            rowData.add(record.getMchId());
            rowData.add(record.getAgentpayOrderId());
            rowData.add(record.getMchOrderNo());
            rowData.add(record.getAccountName());
            rowData.add(record.getAccountNo());
            rowData.add(AmountUtil.convertCent2Dollar(record.getAmount()+""));
            rowData.add(AmountUtil.convertCent2Dollar(record.getFee()+""));
            rowData.add(AmountUtil.convertCent2Dollar(record.getSubAmount()+""));
            switch (record.getStatus()){
                case PayConstant.AGENTPAY_STATUS_INIT : rowData.add("待处理"); break;
                case PayConstant.AGENTPAY_STATUS_ING : rowData.add("处理中"); break;
                case PayConstant.AGENTPAY_STATUS_SUCCESS : rowData.add("成功"); break;
                case PayConstant.AGENTPAY_STATUS_FAIL : rowData.add("失败"); break;
                case PayConstant.AGENTPAY_STATUS_WAIT_AUDIT : rowData.add("待审核"); break;
                default: rowData.add("未知"); break;
            }
            switch (record.getAgentpayChannel()){
                case MchConstant.SETT_CHANNEL_PLAT: rowData.add("商户后台"); break;
                case MchConstant.SETT_CHANNEL_API: rowData.add("API接口"); break;
                default: rowData.add("未知"); break;
            }
            rowData.add(DateUtil.date2Str(record.getCreateTime()));
            excelData.add(rowData);
        }

        super.writeExcelStream("代付订单", excelData);

        return null;
    }

    /** 封装公共函数：  处理运营平台选择一种处理方式   **/
    private void processAgentpaySuccess(JSONObject opParam){

        String agentpayOrderId = getStringRequired(opParam, "agentpayOrderId");
        Integer choosePayType = getIntegerRequired(opParam, "choosePayType"); //打款方式

        MchAgentpayRecord record = commonService.mchAgentpayService.findByAgentpayOrderId(agentpayOrderId);
        if(record == null || record.getStatus() != PayConstant.AGENTPAY_STATUS_WAIT_AUDIT){
            throw new ServiceException(RetEnum.RET_COMM_RECORD_NOT_EXIST);
        }

        // 设置操作人ID和姓名
        record.setOperatorUserId(this.getUser().getId()+"");
        record.setOperatorName(this.getUser().getName());

        if(choosePayType == 1){ //选择一种银行卡 或通道

            Integer confirmPassageId = getIntegerRequired(opParam, "confirmPassageId");
            Integer confirmApaId = getIntegerRequired(opParam, "confirmApaId");
            String confirmTccardAccountNo = getString(opParam, "confirmTccardAccountNo");

            record.setConfirmPassageId(confirmPassageId);
            record.setConfirmPassageAccountId(confirmApaId);
            record.setTccardAccountNo(confirmTccardAccountNo);

            AgentpayPassage passage = commonService.agentpayPassageService.findById(confirmPassageId);
            if(passage == null){
                throw new ServiceException(RetEnum.RET_COMM_RECORD_NOT_EXIST);
            }
        }else if(choosePayType == 2){ //多张银行卡

            JSONArray arrays = JSONArray.parseArray(getStringRequired(opParam, "multipleCardListStr"));
            if(arrays.size() <= 0){
                throw new ServiceException(RetEnum.RET_SERVICE_BANK_CARD_NULL);
            }

            Long allAmount = 0L;
            for (Object o : arrays) {
                JSONObject card = (JSONObject)o;
                Long amountL = Long.parseLong(AmountUtil.convertDollar2Cent(card.getString("amount")));
                allAmount += amountL;
                card.put("amountL", amountL);
            }

            if(!allAmount.equals(record.getRemitAmount())){
                throw new ServiceException(RetEnum.RET_SERVICE_AMOUNT_ERROR);
            }
            record.setPsVal("multipleCardList", arrays);

        }else if(choosePayType == 3){ //直接更新为成功！

        }

        //封装计算分润的选择代付通道信息
        record.setPsVal("calProfitRuleType", opParam.getByte("calProfitRuleType"));
        record.setPsVal("calProfitRuleTypeAgentpayPassageId", opParam.getInteger("calProfitRuleTypeAgentpayPassageId"));
        record.setPsVal("calProfitRuleTypeAgentpayPassageAccountId", opParam.getInteger("calProfitRuleTypeAgentpayPassageAccountId"));

        rpcCommonService.rpcXxPayAgentpayService.auditOk(record, choosePayType);

    }

    /** 代付审核允许的打款方式 **/
    @RequestMapping("/getAgentpayChoosePayTypeConfig")
    @ResponseBody
    public ResponseEntity<?> getAgentpayChoosePayType(HttpServletRequest request) {

        JSONObject result = new JSONObject();
        result.put("agentpayChoosePayType", commonService.sysConfigService.getDBAgentpayConfig().getAgentpayChoosePayType());
        result.put("agentpaySnatchFlag", commonService.sysConfigService.getDBAgentpayConfig().getAgentpaySnatchFlag());
        return ResponseEntity.ok(XxPayPageRes.buildSuccess(result));
    }



    /**
     * 代付补单（将代付改为成功或失败,该方法很暴力,不考虑之前什么状态直接修改）
     * @return
     */
    @RequestMapping("/reissue")
    @ResponseBody
    @MethodLog( remark = "代付补单" )
    public ResponseEntity<?> reissue(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        String agentpayOrderId = getStringRequired(param, "agentpayOrderId");
        _log.info("[代付补单]开始agentpayOrderId={}", agentpayOrderId);
//        // 判断谷歌验证码
//        Long code = getLongRequired(param, "code");
//        _log.info("[代付补单]谷歌code:{}", code);
//        checkGoogleCode(getUser().getId(), code);
        String superPassword = getStringRequired(param, "superPassword");
        if(!checkMgrSuperPwd(superPassword)) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MGR_SUPER_PASSWORD_NOT_MATCH));
        }

        SysUser sysUser = commonService.sysService.findByUserId(getUser().getId());
        // IP验证
        String ip = IPUtility.getClientIp(request);
        _log.info("[代付补单]ip:{}", ip);

        if (StringUtils.isNotEmpty(sysUser.getLoginWhiteIp())) {
            //获取当前用户IP
            Boolean result = XXPayUtil.ipAllow4Strong(ip, sysUser.getLoginWhiteIp(), null);
            if (!result) {
                _log.info("当前登录用户IP不在白名单中,userName={},requestIp={},loginWhiteIp={}", sysUser.getUserName(), ip, sysUser.getLoginWhiteIp());
                throw new ServiceException(RetEnum.RET_MGR_USER_IP_LIMIT);
            }
        }

        Byte status = getByteRequired(param, "reissueStatus"); // 必须为成功或失败
        String isNotifyMchStr = getStringRequired(param, "isNotifyMch");  // 是否通知商户
        boolean isNotifyMch = false;
        if("true".equalsIgnoreCase(isNotifyMchStr)) {
            isNotifyMch = true;
        }

        _log.info("[代付补单]agentpayOrderId={},status={},isNotifyMch={}", agentpayOrderId, status, isNotifyMch);
        if(status != PayConstant.AGENTPAY_STATUS_FAIL && status != PayConstant.AGENTPAY_STATUS_SUCCESS) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_COMM_OPERATION_FAIL, "状态必须为成功或失败"));
        }

        QueryRetMsg queryRetMsg = null;
        if(status == PayConstant.AGENTPAY_STATUS_SUCCESS){
            queryRetMsg = QueryRetMsg.confirmSuccess(null);
        }else if(status == PayConstant.AGENTPAY_STATUS_FAIL){
            queryRetMsg = QueryRetMsg.confirmFail();
        }else{
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_COMM_OPERATION_FAIL, "状态必须为成功或失败"));
        }

        rpcCommonService.rpcXxPayAgentpayService.doReissue(agentpayOrderId, queryRetMsg, isNotifyMch);
        _log.info("[代付补单]完成,agentpayOrderId={}", agentpayOrderId);
        return ResponseEntity.ok(BizResponse.buildSuccess());
    }



    /**
     * 前端详情页银行卡显示规则
     * 如果是超级管理员：可看见完整卡号
     * 如果开启了抢单模式：状态是人工处理时可查看完成卡号,其他状态不可见
     * @param mchAgentpayRecord
     * @return
     */
    String getCardNo4View(MchAgentpayRecord mchAgentpayRecord) {
        String cardNo = mchAgentpayRecord.getAccountNo();
        if(isSupAdmin()) return cardNo;
        if(isEnableSnatch()) {
            if(mchAgentpayRecord.getStatus() == PayConstant.AGENTPAY_STATUS_WAIT_AUDIT
                    && StringUtils.isNotBlank(mchAgentpayRecord.getSnatchUserId())
                    && mchAgentpayRecord.getSnatchUserId().equals(getUser().getId()+"")){
                return cardNo;
            }
        }else {
            if(mchAgentpayRecord.getStatus() == PayConstant.AGENTPAY_STATUS_WAIT_AUDIT){
                return cardNo;
            }
        }
        return StrUtil.str2Star3(cardNo, 4, 4, 4);
    }

    /**
     * 是否开启抢单模式
     * @return
     */
    boolean isEnableSnatch() {
        DBAgentpayConfig config = this.commonService.sysConfigService.getDBAgentpayConfig();
        return config.getAgentpaySnatchFlag() == MchConstant.PUB_YES;
    }

    /**
     * 前端列表页银行卡显示规则
     * 如果是超级管理员：可看见完整卡号
     * 其他角色：不可见完整卡号
     * @param superAdmin
     * @param cardNo
     * @return
     */
    String getCardNo4List(byte superAdmin, String cardNo) {
        boolean isSupAdmin = superAdmin == MchConstant.PUB_YES;
        if(isSupAdmin) return cardNo;
        return StrUtil.str2Star3(cardNo, 4, 4, 4);
    }

}
